#include "Canvas.h"
#include "Animation.h"
#include "effect.h"
#include "text.h"
#include "Widget.h"
#include "misc.h"
#include "hash.h"
#include "resource.h"
#include "movement_line.h"
#include "effect_alpha.h"
#include "dirtyrect.h"
#include "animation_demo.h"
#include "scriptinterface.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_mixer.h>
using namespace animationagent;


static const Uint32 TICK_INTERVAL = 20;
static Uint32 next_time = 0;
static bool running = true;



Uint32 time_left(void)
{
    Uint32 now;

    now = SDL_GetTicks();
    if(next_time <= now)
        return 0;
    else
        return next_time - now;
}

#if 0
struct TimerCbParam
{
    misc::SimpleList<ActionNode *> *actionlist;
    misc::GHashTable *widgethash;
    Uint32 start_time;
};


void process_action(ActionNode *action, misc::GHashTable *widgettable);

Uint32 action_timer_callback(Uint32 interval, void *param)
{
    TimerCbParam *p = static_cast<TimerCbParam *>(param);
    //action loop
    while (!p->actionlist->empty()) {
        ActionNode *node = p->actionlist->get_front();
        if (node->timestamp + p->start_time <= SDL_GetTicks()) {
            printf("do action:start=%u, now=%u\n", p->start_time, SDL_GetTicks());
            p->actionlist->pop_front();
            process_action(node, p->widgethash);
            delete node;
            node = NULL;
        } else {
            break;
        }
    }
    return interval;
}
#endif

SDL_Surface *load_image(const char *path)
{
    SDL_Surface *loaded;
    SDL_Surface *converted;

    loaded = IMG_Load(path);
    converted = SDL_DisplayFormatAlpha(loaded);
    SDL_FreeSurface(loaded);
    return converted;
}

SDL_Surface *load_image_with_colorkey(const char *path, Uint8 r, Uint8 g, Uint8 b)
{
    SDL_Surface *loaded;
    SDL_Surface *converted;

    loaded = IMG_Load(path);
    SDL_SetColorKey(loaded, SDL_SRCCOLORKEY | SDL_RLEACCEL,
                    SDL_MapRGB(loaded->format, r, g, b));
    converted = SDL_DisplayFormatAlpha(loaded);
    SDL_FreeSurface(loaded);

#if 0
    loaded = converted;
    SDL_SetColorKey(loaded, SDL_SRCCOLORKEY | SDL_RLEACCEL,
                    SDL_MapRGB(loaded->format, 0xff, 0x00, 0xff));
    converted = SDL_DisplayFormatAlpha(loaded);
    SDL_FreeSurface(loaded);
#endif

    loaded = converted;
    converted = SDL_DisplayFormat(loaded);
    SDL_FreeSurface(loaded);

    return converted;
}

void update_widget(Widget *w, void *param, void *param2)
{
    if (w == NULL || param == NULL) {
        return;
    }
    w->update();
}

void draw_widget(Widget *w, void *param, void *param2)
{
    if (w == NULL || param == NULL) {
        return;
    }
    SDL_Surface *screen = (SDL_Surface *)param;
    w->draw(screen);
}

void handle_user_event(SDL_Event *e)
{
    const char *objid = (const char *)e->user.data1;
    switch (e->user.code) {
    case ON_MOVE_FINISH:
        printf("'%s' finish move at: %u\n", objid, SDL_GetTicks());
        break;
    case ON_ANIM_FINISH:
        break;
    case ON_FADEALPHA_FINISH:
        break;
    default:
        break;
    }
}

void handle_event(SDL_Event *e)
{
    switch (e->type) {
    case SDL_QUIT:
        running = false;
        break;
    case SDL_USEREVENT:
        handle_user_event(e);
        break;
    default:
        break;
    }
}

void process_action(ActionNode *action, misc::GHashTable *widgettable)
{
    Widget *w = NULL;
    //Canvas *c = NULL;
    if (action == NULL || widgettable == NULL) {
        return;
    }
    w = static_cast<Widget *>(widgettable->g_hash_table_lookup(action->objectID));
    if (w == NULL) {
        return;
    }
    switch (action->type) {
    case ACTION_MOVE:
        //w->moveto(action->param.point.x, action->param.point.y, action->duration);
        w->set_movement(new MovementLine(w->get_allocation().x, w->get_allocation().y,
                                         action->param.point.x, action->param.point.y, action->duration));
        break;
    case ACTION_HIDE:
        w->set_visible(false);
        break;
    case ACTION_SHOW:
        w->set_visible(true);
        break;
    case ACTION_FADE_OUT:
        /*c = dynamic_cast<Canvas *>(w);
        if (c != NULL) {
            c->alpha_fade_out(action->duration);
        }*/
        w->set_effect(new EffectAlpha(0xff, 0x00, action->duration));
        break;
    case ACTION_FADE_IN:
        /*c = dynamic_cast<Canvas *>(w);
        if (c != NULL) {
            c->alpha_fade_in(action->duration);
        }*/
        w->set_effect(new EffectAlpha(0x00, 0xff, action->duration));
        break;
    case ACTION_SETCOLOR:
        {
            SDL_Color col;
            col.r = action->param.color.r;
            col.g = action->param.color.g;
            col.b = action->param.color.b;
            w->set_fncolor(col);
        }
        break;
    case ACTION_SETTEXT:
        {
            Text *t = dynamic_cast<Text *>(w);
            if (t != NULL) {
                t->set_text(action->param.str);
            }
        }
        break;
    default:
        break;
    }
}

static inline ActionNode *add_action(misc::SimpleList<ActionNode *> *actionlist, const char *objid)
{
    ActionNode *node = NULL;
    if (objid == NULL) {
        throw "NULL objid!";
    }
    node = new ActionNode();
    strncpy(node->objectID, objid, sizeof(node->objectID) - 1);
    node->objectID[sizeof(node->objectID) - 1] = '\0';
    actionlist->push_back(node);
    return node;
}

void action_add_show(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_SHOW;
        node->timestamp = timestamp;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_hide(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_HIDE;
        node->timestamp = timestamp;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_move(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp,
                Uint32 duration, Sint16 x, Sint16 y)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_MOVE;
        node->timestamp = timestamp;
        node->duration = duration;
        node->param.point.x = x;
        node->param.point.y = y;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_fadein(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp, Uint32 duration)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_FADE_IN;
        node->timestamp = timestamp;
        node->duration = duration;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_fadeout(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp, Uint32 duration)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_FADE_OUT;
        node->timestamp = timestamp;
        node->duration = duration;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_setcolor(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp, Uint8 r, Uint8 g, Uint8 b)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_SETCOLOR;
        node->timestamp = timestamp;
        node->param.color.r = r;
        node->param.color.g = g;
        node->param.color.b = b;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

void action_add_settext(misc::SimpleList<ActionNode *> *actionlist,
                const char *objid, Uint32 timestamp, const char *str)
{
    try {
        ActionNode *node = add_action(actionlist, objid);
        node->type = ACTION_SETTEXT;
        node->timestamp = timestamp;
        node->param.str = str;
    } catch ( const char *e ) {
        fprintf(stderr, "%s\n", e);
    }
}

#ifdef _MSC_VER
#include <tchar.h>
//int _tmain(int argc, _TCHAR* argv[])
#else
//int main (int argc, char *argv[])
#endif
int main (int argc, char *argv[])
{
    SDL_Surface *screen = NULL;
    SDL_Event event;
    misc::SimpleList<ActionNode *> actionlist;
    misc::GHashTable widgethash(misc::g_str_hash, misc::g_str_equal);
    helper::ResourceManager resourcemanager;
    Uint32 start_time = 0;
    Uint32 debug_time = 0;

    if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER)==-1)) {
        exit(1);
    }
    atexit(SDL_Quit);

    if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) == -1) {
        printf("Mix_OpenAudio: %s\n", Mix_GetError());
        exit(2);
    }

    screen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
    if ( screen == NULL ) {
        printf("SDL_SetVideoMode: %s\n", SDL_GetError());
        exit(3);
    }

    if(TTF_Init() == -1) {
        printf("TTF_Init: %s\n", TTF_GetError());
        exit(4);
    }

    using namespace script;
    if (script_lua_init(&actionlist) == -1) {
        printf("init lua error\n");
        exit(5);
    }

    if (script_lua_dofile("./script/action.lua") == -1) {
        exit(6);
    }


    Widget layer_background;
    Widget layer_sprite;
    Widget layer_front;
    layer_background.set_id("layer_background");
    layer_sprite.set_id("layer_spirit");
    layer_front.set_id("layer_front");
    /*test data*/
#if 0
    Canvas *background = new Canvas(load_image("./images/background.png"));
    wtree_add_child(&layer_background, background);

    Canvas *canvas;
    canvas = new Canvas(load_image_with_colorkey("./images/1.png", 0xff, 0x00, 0xff));
    canvas->set_alpha(0xff);
    canvas->set_colorkey(0x00, 0xff, 0xff);
    wtree_add_child(&layer_sprit, canvas);
    canvas->moveto(640, 480, 20000);

    Animation *anim;
    anim = new Animation();
    anim->add_frame(load_image("./images/1.png"));
    anim->add_frame(load_image("./images/2.png"));
    anim->add_frame(load_image("./images/3.png"));
    anim->add_frame(load_image("./images/4.png"));
    anim->set_alpha(0x80);
    anim->set_colorkey(0x00, 0xff, 0xff);
    anim->set_frame_rate(200);
    anim->set_playstyle(Animation::LOOP);
    anim->set_allocation(0, 0, 450, 400);
    wtree_add_child(&layer_sprit, anim);
    anim->moveto(600, 400, 15000);
#endif

    TTF_Font *font;
    TTF_Font *font2;
    font = TTF_OpenFont("./font/wqy-zenhei-gb2312.ttf", 72);
    if(!font) {
        printf("TTF_OpenFont: %s\n", TTF_GetError());
        exit(5);
    }
    font2 = TTF_OpenFont("./font/wqy-zenhei-gb2312.ttf", 72);
    if(!font2) {
        printf("TTF_OpenFont: %s\n", TTF_GetError());
        exit(5);
    }
    SDL_Color fncolor={0xff,0xff,0xff};
    SDL_Color bgcolor={0x00,0xff,0xff};

    try {
        resourcemanager.load_textcollection("./script/texts.ch");

        //build object
        Canvas *canvas = NULL;
        canvas = new Canvas(resourcemanager.load_image("./images/worldmap.png"));
        canvas->set_id("worldmap");
        canvas->set_visible(false);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/anhunzhenmap.png"));
        canvas->set_id("anhunzhenmap");
        canvas->set_visible(false);
        canvas->set_level(-1);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/anhunzhen.png"));
        canvas->set_id("anhunzhen");
        canvas->set_visible(false);
        canvas->set_level(-2);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/flying01.png"));
        canvas->set_id("flying01");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/flying11.png"));
        canvas->set_id("flying11");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/flying23.png"));
        canvas->set_id("flying23");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/flying26.png"));
        canvas->set_id("flying26");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/flying29.png"));
        canvas->set_id("flying29");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/18moon.png"));
        canvas->set_id("18moon");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/lingfeng.png"));
        canvas->set_id("lingfeng");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/windy.png"));
        canvas->set_id("windy");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/18moon2.png"));
        canvas->set_id("18moon2");
        canvas->set_visible(false);
        canvas->set_level(1);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/lingfeng2.png"));
        canvas->set_id("lingfeng2");
        canvas->set_visible(false);
        canvas->set_level(2);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/windy2.png"));
        canvas->set_id("windy2");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/avilia1.png"));
        canvas->set_id("avilia1");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/avilia2.png"));
        canvas->set_id("avilia2");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/slaindragon1.png"));
        canvas->set_id("slaindragon1");
        canvas->set_visible(false);
        canvas->set_level(0);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/ice_mask.png"));
        canvas->set_id("ice_mask");
        canvas->set_visible(false);
        canvas->set_level(5);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/ice_pose.png"));
        canvas->set_id("ice_pose");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/fire_mask.png"));
        canvas->set_id("fire_mask");
        canvas->set_visible(false);
        canvas->set_level(5);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/fire_pose.png"));
        canvas->set_id("fire_pose");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/raptor_mask.png"));
        canvas->set_id("raptor_mask");
        canvas->set_visible(false);
        canvas->set_level(5);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/raptor_pose.png"));
        canvas->set_id("raptor_pose");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/angle_mask.png"));
        canvas->set_id("angle_mask");
        canvas->set_visible(false);
        canvas->set_level(5);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/angle_pose.png"));
        canvas->set_id("angle_pose");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/lisha.png"));
        canvas->set_id("lisha");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/manks.png"));
        canvas->set_id("manks");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/rick.png"));
        canvas->set_id("rick");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/shadow.png"));
        canvas->set_id("shadow");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/ben.png"));
        canvas->set_id("ben");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/captin.png"));
        canvas->set_id("captin");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/fork.png"));
        canvas->set_id("fork");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_chen.png"));
        canvas->set_id("y_chen");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_zhan.png"));
        canvas->set_id("y_zhan");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_feng.png"));
        canvas->set_id("y_feng");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_luren1.png"));
        canvas->set_id("y_luren1");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_ying.png"));
        canvas->set_id("y_ying");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_luren2.png"));
        canvas->set_id("y_luren2");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_ling.png"));
        canvas->set_id("y_ling");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/y_meng.png"));
        canvas->set_id("y_meng");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_shadow.png"));
        canvas->set_id("v_shadow");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_wizard.png"));
        canvas->set_id("v_wizard");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_xiuyi.png"));
        canvas->set_id("v_xiuyi");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_meng.png"));
        canvas->set_id("v_meng");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_zhonglong.png"));
        canvas->set_id("v_zhonglong");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_black.png"));
        canvas->set_id("v_black");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_meng2.png"));
        canvas->set_id("v_meng2");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/v_yan.png"));
        canvas->set_id("v_yan");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        canvas = new Canvas(resourcemanager.load_image("./images/wwbw.png"));
        canvas->set_id("wwbw");
        canvas->set_visible(false);
        canvas->set_level(4);
        widgethash.g_hash_table_insert(const_cast<char *>(canvas->get_id()), canvas);
        layer_sprite.wtree_add_child(canvas);

        Text *text = NULL;
        text = new Text(font);
        text->set_id("text1");
        text->set_fncolor(fncolor);
        text->set_bgcolor(bgcolor);
        widgethash.g_hash_table_insert(const_cast<char *>(text->get_id()), text);
        layer_front.wtree_add_child(text);

        text = new Text(font2);
        text->set_id("text2");
        text->set_fncolor(fncolor);
        text->set_bgcolor(bgcolor);
        widgethash.g_hash_table_insert(const_cast<char *>(text->get_id()), text);
        layer_front.wtree_add_child(text);

        text = new Text(font2);
        text->set_id("text3");
        text->set_fncolor(fncolor);
        text->set_bgcolor(bgcolor);
        widgethash.g_hash_table_insert(const_cast<char *>(text->get_id()), text);
        layer_front.wtree_add_child(text);

        text = new Text(font2);
        text->set_id("text4");
        text->set_fncolor(fncolor);
        text->set_bgcolor(bgcolor);
        widgethash.g_hash_table_insert(const_cast<char *>(text->get_id()), text);
        layer_front.wtree_add_child(text);

        text = new Text(font2);
        text->set_id("text5");
        text->set_fncolor(fncolor);
        text->set_bgcolor(bgcolor);
        widgethash.g_hash_table_insert(const_cast<char *>(text->get_id()), text);
        layer_front.wtree_add_child(text);

#if 0
        Animation *anim = NULL;
        anim = new Animation();
        anim->add_frame(resourcemanager.load_image("./images/1.png"));
        anim->add_frame(resourcemanager.load_image("./images/2.png"));
        anim->add_frame(resourcemanager.load_image("./images/3.png"));
        anim->add_frame(resourcemanager.load_image("./images/4.png"));
        anim->set_id("spirit");
        AnimationSequence *animsequence = new AnimationSequence("normal");
        animsequence->set_frame_rate(200);
        animsequence->set_playstyle(AnimationSequence::LOOP);
        animsequence->append_index(0);
        animsequence->append_index(1);
        animsequence->append_index(2);
        animsequence->append_index(3);
        anim->add_sequence(animsequence);
        anim->set_allocation(0, 0, 450, 400);
        anim->set_visible(false);
        widgethash.g_hash_table_insert(const_cast<char *>(anim->get_id()), anim);
        layer_front.wtree_add_child(anim);
#endif

        //load music
        resourcemanager.load_music("./music/LONG.ogg");
        /*end test data*/
    } catch ( char *str ) {
        fprintf(stderr, "%s\n", str);
        exit(7);
    } catch ( const char *str) {
        fprintf(stderr, "%s\n", str);
        exit(7);
    }

    //play music
    if(Mix_PlayMusic(resourcemanager.get_music("LONG.ogg"), -1)==-1) {
        printf("Mix_PlayMusic: %s\n", Mix_GetError());
    }

    start_time = SDL_GetTicks();
    debug_time = 0;
    //main loop
    while (running) {
        //event loop
        while (SDL_PollEvent(&event)) {
            handle_event(&event);
        }
        while (!actionlist.empty()) {
            ActionNode *node = actionlist.get_front();
            if (node->timestamp + start_time <= SDL_GetTicks() + debug_time) {
                printf("do action:start=%u, now=%u\n", start_time, SDL_GetTicks());
                actionlist.pop_front();
                process_action(node, &widgethash);
                delete node;
                node = NULL;
            } else {
                break;
            }
        }
        SDL_Delay(time_left());

        /*------------------------*/
        Widget::wtree_levelorder_traversal(&layer_background, update_widget, screen, NULL);
        Widget::wtree_levelorder_traversal(&layer_sprite, update_widget, screen, NULL);
        Widget::wtree_levelorder_traversal(&layer_front, update_widget, screen, NULL);
        /*------------------------*/
        if (DirtyRect::is_all_dirty()) {
            SDL_FillRect(screen, NULL, 0);
        } else {
            int rect_num = DirtyRect::get_number();
            int i;
            for (i=0; i<rect_num; i++) {
                SDL_FillRect(screen, DirtyRect::get_rect(i), 0);
            }
        }
        /*------------------------*/
        Widget::wtree_levelorder_traversal(&layer_background, draw_widget, screen, NULL);
        Widget::wtree_levelorder_traversal(&layer_sprite, draw_widget, screen, NULL);
        Widget::wtree_levelorder_traversal(&layer_front, draw_widget, screen, NULL);
        /*------------------------*/
        SDL_Flip(screen);
        DirtyRect::clear();
        next_time += TICK_INTERVAL;
        next_time = std::max(next_time, SDL_GetTicks());
    }

    Mix_HaltMusic();
    //while(!Mix_FadeOutMusic(3000) && Mix_PlayingMusic()) {
    //    // wait for any fades to complete
    //    SDL_Delay(100);
    //}

    resourcemanager.free_all();
    SDL_FreeSurface(screen);
    screen = NULL;
    Mix_CloseAudio();
    script_lua_close();
    TTF_Quit();
    /* Shutdown all subsystems */
    SDL_Quit();
    return 0;
}

